package org.amphiprion.kidcalendar.entity;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import org.amphiprion.kidcalendar.entity.Period.PeriodType;

public class DateRule implements Rule {
	private String type;
	private String value;
	private String start;
	private List<Rule> rules = new ArrayList<Rule>();

	@Override
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public String getStart() {
		return start;
	}

	public void setStart(String start) {
		this.start = start;
	}

	@Override
	public List<Rule> getSubRules() {
		return rules;
	}

	@Override
	public Period verifyDate(Date date) {
		if ("EVERY_X_WEEKEND".equals(type)) {
			try {
				// System.out.println("       >>> START  EVERY_X_WEEKEND");
				Calendar cDate = new GregorianCalendar();
				cDate.setTime(date);

				Date startDate = new SimpleDateFormat("yyyy-MM-dd").parse(start);
				Calendar cstart = new GregorianCalendar();
				cstart.setTime(startDate);
				cstart.set(Calendar.HOUR_OF_DAY, 0);
				cstart.set(Calendar.MINUTE, 0);
				cstart.set(Calendar.SECOND, 0);
				cstart.set(Calendar.MILLISECOND, 0);

				Calendar cEnd = new GregorianCalendar();
				cEnd.setTime(startDate);
				cEnd.set(Calendar.HOUR_OF_DAY, 23);
				cEnd.set(Calendar.MINUTE, 59);
				cEnd.set(Calendar.SECOND, 59);
				cEnd.set(Calendar.MILLISECOND, 0);
				cEnd.add(Calendar.DAY_OF_YEAR, 1);

				// TODO optimiser (faire une adition au lieu d'un while
				// si la date de conf est dans le future
				// System.out.println("      avant1 " + cstart.getTime());
				int jump = Integer.parseInt(value) * 7;
				while (cstart.after(cDate)) {
					cstart.add(Calendar.DAY_OF_YEAR, -jump);
					cEnd.add(Calendar.DAY_OF_YEAR, -jump);
				}
				// System.out.println("      apres1 " + cstart.getTime());
				// System.out.println("      avant2 " + cstart.getTime());
				while (cEnd.before(cDate)) {
					cstart.add(Calendar.DAY_OF_YEAR, jump);
					cEnd.add(Calendar.DAY_OF_YEAR, jump);
				}
				// System.out.println("      apres2 " + cstart.getTime());

				// System.out.println("       >>> END EVERY_X_WEEKEND");
				if (cstart.before(cDate)) {
					// given date between start & end
					return new Period(cstart.getTime(), cEnd.getTime(), this, PeriodType.WEEKEND);
				}
				return null;
			} catch (ParseException e) {
				e.printStackTrace();
				return null;
			}
		} else if ("YEAR".equals(type)) {
			Calendar cDate = new GregorianCalendar();
			cDate.setTime(date);
			int year = cDate.get(Calendar.YEAR);
			if ("EVEN".equals(value)) {
				if (year % 2 == 0) {
					cDate.set(Calendar.HOUR_OF_DAY, 0);
					cDate.set(Calendar.MINUTE, 0);
					cDate.set(Calendar.SECOND, 0);
					cDate.set(Calendar.MILLISECOND, 0);

					cDate.set(Calendar.DAY_OF_MONTH, 1);
					cDate.set(Calendar.MONTH, 0);
					Period period = new Period();
					period.setFrom(cDate.getTime());
					cDate.set(Calendar.DAY_OF_MONTH, 31);
					cDate.set(Calendar.MONTH, 11);
					period.setTo(cDate.getTime());
					period.setAssociatedRule(this);
					period.setType(PeriodType.OTHER);
					return period;
				} else {
					return null;
				}
			} else if ("ODD".equals(value)) {
				if (year % 2 == 1) {
					cDate.set(Calendar.HOUR_OF_DAY, 0);
					cDate.set(Calendar.MINUTE, 0);
					cDate.set(Calendar.SECOND, 0);
					cDate.set(Calendar.MILLISECOND, 0);

					cDate.set(Calendar.DAY_OF_MONTH, 1);
					cDate.set(Calendar.MONTH, 0);
					Period period = new Period();
					period.setFrom(cDate.getTime());
					cDate.set(Calendar.DAY_OF_MONTH, 31);
					cDate.set(Calendar.MONTH, 11);
					period.setTo(cDate.getTime());
					period.setAssociatedRule(this);
					period.setType(PeriodType.OTHER);
					return period;
				} else {
					return null;
				}
			} else {
				int val = Integer.parseInt(value);
				if (year == val) {
					cDate.set(Calendar.HOUR_OF_DAY, 0);
					cDate.set(Calendar.MINUTE, 0);
					cDate.set(Calendar.SECOND, 0);
					cDate.set(Calendar.MILLISECOND, 0);

					cDate.set(Calendar.DAY_OF_MONTH, 1);
					cDate.set(Calendar.MONTH, 0);

					Period period = new Period();
					period.setFrom(cDate.getTime());
					cDate.set(Calendar.DAY_OF_MONTH, 31);
					cDate.set(Calendar.MONTH, 11);
					period.setTo(cDate.getTime());
					period.setAssociatedRule(this);
					period.setType(PeriodType.OTHER);
					return period;
				} else {
					return null;
				}
			}
		} else if ("WEEKEND_IN_MONTH".equals(type)) {
			Calendar cDate = new GregorianCalendar();
			cDate.setTime(date);
			int weekday = cDate.get(Calendar.DAY_OF_WEEK);
			if (weekday == Calendar.SATURDAY) {
				cDate.add(Calendar.DAY_OF_YEAR, 1);
			} else if (weekday != Calendar.SUNDAY) {
				return null;
			}
			int numWeek = (cDate.get(Calendar.DAY_OF_MONTH) - 1) / 7 + 1;
			if (numWeek == Integer.parseInt(value)) {
				cDate.set(Calendar.HOUR_OF_DAY, 0);
				cDate.set(Calendar.MINUTE, 0);
				cDate.set(Calendar.SECOND, 0);
				cDate.set(Calendar.MILLISECOND, 0);

				cDate.add(Calendar.DAY_OF_YEAR, -1);
				Period period = new Period();
				period.setFrom(cDate.getTime());
				cDate.add(Calendar.DAY_OF_YEAR, +1);
				cDate.set(Calendar.HOUR_OF_DAY, 23);
				cDate.set(Calendar.MINUTE, 59);
				cDate.set(Calendar.SECOND, 59);
				cDate.set(Calendar.MILLISECOND, 0);

				period.setTo(cDate.getTime());
				period.setAssociatedRule(this);
				period.setType(PeriodType.WEEKEND);
				return period;

			} else {
				return null;
			}
		}
		return null;
	}

	// @Override
	// public Period getPeriod(Date date) {
	// Period period = null;
	// if ("EVERY_X_WEEKEND".equals(type) || "WEEKEND_IN_MONTH".equals(type)) {
	// Calendar cDate = new GregorianCalendar();
	// cDate.setTime(date);
	// cDate.set(Calendar.HOUR_OF_DAY, 0);
	// cDate.set(Calendar.MINUTE, 0);
	// cDate.set(Calendar.SECOND, 0);
	// int weekday = cDate.get(Calendar.DAY_OF_WEEK);
	// if (weekday == Calendar.SUNDAY) {
	// cDate.add(Calendar.DAY_OF_YEAR, -1);
	// period = new Period();
	// period.setFrom(cDate.getTime());
	// cDate.add(Calendar.DAY_OF_YEAR, +1);
	// period.setTo(cDate.getTime());
	// } else if (weekday == Calendar.SATURDAY) {
	// period = new Period();
	// period.setFrom(cDate.getTime());
	// cDate.add(Calendar.DAY_OF_YEAR, +1);
	// period.setTo(cDate.getTime());
	// }
	// return period;
	// } else if ("YEAR".equals(type)) {
	// Calendar cDate = new GregorianCalendar();
	// cDate.setTime(date);
	// cDate.set(Calendar.HOUR_OF_DAY, 0);
	// cDate.set(Calendar.MINUTE, 0);
	// cDate.set(Calendar.SECOND, 0);
	// cDate.set(Calendar.DAY_OF_MONTH, 1);
	// cDate.set(Calendar.MONTH, 0);
	// period = new Period();
	// period.setFrom(cDate.getTime());
	// cDate.set(Calendar.DAY_OF_MONTH, 31);
	// cDate.set(Calendar.MONTH, 11);
	// period.setTo(cDate.getTime());
	// return period;
	// }
	// return null;
	// }
}
